//
/**
*
*File name:		LXAlertManager.swift
*History:		yoctech create on 2021/7/29       
*Description:
	
*/


import UIKit

open class LXAlertManager: NSObject {
    public static let shared = LXAlertManager()
    
    /// 等待展示弹窗列表
    open var waitList: [LXAlertProtocol] = []
    
    /// 正在展示的弹窗
    open var currentAlert: LXAlertProtocol?
    
    /// 需要过滤的弹框标识数据
    private var filterIdentifiers: [String] = []
    
    ///保持沉默
    open var isSilence:Bool = false {
        didSet {
            LXLog("[弹窗]是否静默:\(isSilence)")
            if isSilence {
                if currentAlert != nil {
                    pause(currentAlert!)
                }
            }else{
                //需要防止重复调用
                if currentAlert == nil {
                    showNextOne()
                }
            }
        }
    }
    

    
    /// 载入新弹窗
    open func push(_ alert:LXAlertProtocol) {
        wait(alert)
        //如果保持静默,直接等待
        if isSilence {
            return
        }
        //如果没有正在展示的弹窗
        if currentAlert == nil {
            //直接展示
            showNextOne()
        }else if currentAlert!.alertLevel < alert.alertLevel {
            //如果正在展示的弹窗优先级没有新的高,就暂停旧的,显示新的
            pause(currentAlert!)
            DispatchQueue.main.asyncAfter(deadline: .now() + currentAlert!.alertAnimationDuration) {
                self.showNextOne()
            }
        }
    }
    
    /// 移除弹窗。
    /// 与暂停弹窗的区别是，移除是彻底移除，显示下一个；暂停是重新放入等待列表，不自动显示下一个
    /// - Parameter alert: 目标弹窗
    open func pop(_ alert:LXAlertProtocol) {
        LXLog("[弹窗]移除弹窗\(type(of: alert))")
        alert.alertHide()
        if let firstIndex = waitList.firstIndex(where: { (obj) -> Bool in
            return obj === alert
        }) {
            waitList.remove(at: firstIndex)
        }
        if currentAlert != nil && currentAlert !== alert {
            return
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + alert.alertAnimationDuration) {
            self.showNextOne()
        }
    }
    
    /// 获取并显示下一个需要展示的弹窗,特别注意,如果单独调用多次,则会展示多个弹窗,需要与pop和pause结合使用
    open func showNextOne() {
        currentAlert = nil
        
        if let firstAlert = waitList.first(where: { (obj) -> Bool in
            guard let alertIdentifier = obj.alertIdentifier else {
                return true
            }
            return !self.filterIdentifiers.contains(alertIdentifier)
        }) {
            self.show(firstAlert)
            LXLog("[弹窗]弹出等待列表符合过滤条件的第一个")
        }
    }
    
    /// 展示弹窗，标记currentAlert为正在展示的弹窗
    /// - Parameter alert: 目标弹窗
    open func show(_ alert:LXAlertProtocol) {
        LXLog("[弹窗]展示弹窗\(type(of: alert))")
        alert.alertShow()
        currentAlert = alert
    }
    
    /// 暂停显示弹窗,把弹窗重新放入wait列表头部,并按照优先级排序;
    /// - Parameter alert: 目标弹窗。如果目标弹窗是currentAlert，需要把currentAlert置空
    open func pause(_ alert:LXAlertProtocol) {
        LXLog("[弹窗]暂停弹窗\(type(of: alert))")
        alert.alertHide()
        waitList.insert(alert, at: 0)
        sortWaitList()
        if currentAlert != nil && currentAlert === alert {
            currentAlert = nil
        }
    }
    
    /// 弹窗放入等待队列,并按照优先级排序
    /// - Parameter alert: 目标弹窗
    open func wait(_ alert:LXAlertProtocol) {
        LXLog("[弹窗]放入队列\(type(of: alert))")
        waitList.append(alert)
        sortWaitList()
    }
    
    /// 删除指定标识的所有弹窗
    /// - Parameter identifier: 标识,如果为nil,则删除所有没有标识的弹窗
    open func removeAlert(with identifier: String?){
        LXLog("[弹窗]移除标识为\(String(describing: identifier))的所有弹窗")

        waitList = waitList.filter { (obj) -> Bool in
            return obj.alertIdentifier != identifier
        }
        if currentAlert != nil && currentAlert?.alertIdentifier == identifier{
            self.pop(currentAlert!)
        }
    }
    
    /// 增加过滤标识,持有该标识的弹窗,在轮到它弹出时会被跳过,已经弹出的会被暂停
    /// - Parameter identifier: 标识
    open func addFilterIdentifier(_ identifier:String) {
        if filterIdentifiers.contains(identifier) {
            return
        }
        filterIdentifiers.append(identifier)
        if currentAlert != nil && currentAlert?.alertIdentifier == identifier{
            pause(currentAlert!)
            DispatchQueue.main.asyncAfter(deadline: .now() + currentAlert!.alertAnimationDuration) {
                self.showNextOne()
            }
        }
    }
    
    /// 移除过滤标识,持有该标识的弹窗,移除过滤标识时会自动弹出
    /// - Parameter identifier: 标识
    open func removeFilterIdentifier(_ identifier:String) {
        if !filterIdentifiers.contains(identifier) {
            return
        }
        //从filterIdentifiers中移除
        filterIdentifiers = filterIdentifiers.filter { (obj) -> Bool in
            return obj != identifier
        }
        //如果有正在展示的弹窗
        if currentAlert != nil {
            var currentIndex = -1
            //遍历列表
            for (index, value) in waitList.enumerated() {
                //如果先遇到持有该identifier的弹窗,那么直接退出遍历,currentIndex不会被赋值
                if value.alertIdentifier == identifier {
                    break
                }
                //如果先遇到currentAlert
                if value === currentAlert {
                    //那么currentIndex就会被赋值
                    currentIndex = index
                }
            }
            //如果currentIndex没有被赋值
            if currentIndex < 0 {
                //说明有优先级更高的弹窗需要展示
                pause(currentAlert!)
                DispatchQueue.main.asyncAfter(deadline: .now() + currentAlert!.alertAnimationDuration + 0.2) {
                    self.showNextOne()
                }
            }
        }
    }
    /// 移除所有过滤标识
    open func clearAllFilterIdentifiers() {
        if filterIdentifiers.isEmpty {
            return
        }
        filterIdentifiers.removeAll()
        //判断是否有正在显示的弹窗
        if currentAlert != nil {
            //拿到正在显示的弹窗的index
            if let currentIndex = waitList.firstIndex(where: { (obj) -> Bool in
                return obj === currentAlert
            }) {
                //如果index>0,表示有更高优先级或者更早进入队列的弹窗因为过滤没有展示,此时需要优先展示
                if currentIndex > 0 {
                    pause(currentAlert!)
                    DispatchQueue.main.asyncAfter(deadline: .now() + currentAlert!.alertAnimationDuration + 0.2) {
                        self.showNextOne()
                    }
                }
            }
        }
    }
    
    /// wait列表排序
    private func sortWaitList() {
        LXLog("[弹窗]按优先级排序")
        waitList.sort { (lhs, rhs) -> Bool in
            return lhs.alertLevel > rhs.alertLevel
        }
    }
    
}
